package attr

import (
	"time"

	"gddgame.cc/galaxy/common/dsl/game"
	"gddgame.cc/galaxy/utils/orm"
)

type AttrData struct {
	// attr不会修改，保持引用即可
	Attrs         []*Attr
	SettingsAttrs []SettingAttr
	AttrGroups    []*AttrGroup

	AttrMap map[int]*Attr

	attrModel      *orm.Model
	attrGroupModel *orm.Model

	dataIndexMap map[int]*Attr
	dataIdMap    map[int]int

	attrKeyIndexMap map[string]int
	attrKeyIdMap    map[string]int

	battleIndexMap map[int]*Attr
	battleIdMap    map[int]int
}

func GetAttrData(env *game.Environment) (*AttrData, error) {
	var err error
	data := &AttrData{}

	attrProvider := &game.DataProvider{
		Name:  "attr",
		Array: true,
		Get: func() (provides interface{}, err error) {
			return data.Attrs, nil
		},
	}
	env.RegisterData(attrProvider)

	attrGroupProvider := &game.DataProvider{
		Name:  "attrGroup",
		Array: true,
		Get: func() (i interface{}, err error) {
			return data.AttrGroups, nil
		},
	}
	env.RegisterData(attrGroupProvider)

	if data.attrModel, data.SettingsAttrs, data.Attrs, err = getAttrData(env, attrProvider); err != nil {
		return nil, err
	}
	if data.attrGroupModel, _, data.AttrGroups, err = getAttrGroupData(env, attrGroupProvider); err != nil {
		return nil, err
	}

	data.initAttr()
	return data, nil
}
func getAttrData(env *game.Environment, provider *game.DataProvider) (*orm.Model, []SettingAttr, []*Attr, error) {
	var err error

	model, err := env.GetModel(SettingAttrName)
	if err != nil {
		return nil, nil, nil, err
	}
	var attrs []SettingAttr
	_, err = model.Query().Order("is_data", orm.ASC).Order("sort", orm.ASC).Order("id", orm.ASC).Find(&attrs)
	if err != nil {
		return nil, nil, nil, err
	}
	attrList := make([]*Attr, len(attrs))
	for i := range attrs {
		attrs[i].ComputeValue()
		attrList[i] = NewAttr(provider, &attrs[i])
	}
	return model, attrs, attrList, nil
}

func getAttrGroupData(env *game.Environment, provider *game.DataProvider) (*orm.Model, []SettingAttrGroup, []*AttrGroup, error) {
	var err error
	model, err := env.GetModel(SettingAttrGroupName)
	if err != nil {
		return nil, nil, nil, err
	}
	var attrGroups []SettingAttrGroup
	_, err = model.Query().Find(&attrGroups)
	if err != nil {
		return nil, nil, nil, err
	}
	attrGroupList := make([]*AttrGroup, len(attrGroups))
	for k := range attrGroups {
		attrGroupList[k] = NewAttrGroup(provider, &attrGroups[k])
	}
	return model, attrGroups, attrGroupList, nil
}

func (attrData *AttrData) initAttr() {
	attrData.AttrMap = make(map[int]*Attr, len(attrData.Attrs))
	for _, attr := range attrData.Attrs {
		attrData.AttrMap[attr.Id] = attr
	}
	attrData.attrKeyIdMap = map[string]int{}
	attrData.attrKeyIndexMap = map[string]int{}
	attrData.dataIndexMap = map[int]*Attr{}
	attrData.dataIdMap = map[int]int{}
	attrData.battleIndexMap = map[int]*Attr{}
	attrData.battleIdMap = map[int]int{}
	for i, attr := range attrData.SettingsAttrs {
		attrData.attrKeyIndexMap[attr.Key] = i
		attrData.attrKeyIdMap[attr.Key] = attr.Id
		if attr.IsData {
			attrData.dataIndexMap[len(attrData.dataIndexMap)] = attrData.AttrMap[attr.Id]
			attrData.dataIdMap[attr.Id] = len(attrData.dataIdMap)
		}

		if attr.IsBattle {
			attrData.battleIndexMap[len(attrData.battleIndexMap)] = attrData.AttrMap[attr.Id]
			attrData.battleIdMap[attr.Id] = len(attrData.battleIdMap)
		}
	}
}

func (attrData *AttrData) GetDataStatMap() map[int]*Attr {
	return attrData.dataIndexMap
}

func (attrData *AttrData) GetDataStatIndex(key string) int {
	id := attrData.KeyToId(key)
	if v, ok := attrData.dataIdMap[id]; ok {
		return v
	}
	return 0
}

func (attrData *AttrData) IdToKey(id int) string {
	return attrData.AttrMap[id].Key
}

func (attrData *AttrData) KeyToId(key string) int {
	return attrData.attrKeyIdMap[key]
}

func (attrData *AttrData) IndexToId(index int) int {
	return attrData.Attrs[index].Id
}

func (attrData *AttrData) ListToMap(list []string) map[int]int {
	result := make(map[int]int, len(list))
	for index, key := range list {
		id := attrData.KeyToId(key)
		result[id] = index
	}
	return result
}

func (attrData *AttrData) BattleIndex(id int) (int, bool) {
	v, ok := attrData.battleIdMap[id]
	return v, ok
}

func (attrData *AttrData) AllData() {

}

func (attrData *AttrData) GetAllAttr(updateTime *time.Time) ([]*Attr, error) {
	if updateTime != nil {
		attrs := make([]*Attr, 0, 5)
		for _, attr := range attrData.Attrs {
			if attr.HasUpdate(updateTime) {
				attrs = append(attrs, attr)
			}
		}
		return attrs, nil
	} else {
		return attrData.Attrs, nil
	}
}

func (attrData *AttrData) GetAllAttrGroup(updateTime *time.Time) ([]*AttrGroup, error) {
	if updateTime != nil {
		attrGroups := make([]*AttrGroup, 0, 5)
		for _, attrGroup := range attrData.AttrGroups {
			if attrGroup.HasUpdate(updateTime) {
				attrGroups = append(attrGroups, attrGroup)
			}
		}
		return attrGroups, nil
	} else {
		return attrData.AttrGroups, nil
	}
}

func (attrData *AttrData) DiffAttr(diff game.IntAbilityMap) map[string]interface{} {
	m := map[string]interface{}{}
	for id, value := range diff {
		attr := attrData.AttrMap[id]
		if attr.IsData || attr.IsBattle {
			continue
		}
		m[attr.Key] = value
	}
	return m
}
